
// 待测试邀请码
const codeEncoded = '33b×85cc×9×a96f6'

/**
 * 技术分析实现
 */
const numList = '1234567890'.split('')
const charList = 'QWERTYUIOPASDFGHJKLZXCVBNM'.toLowerCase().split('')
const testList = [].concat(numList, charList)
const firstCh = testList[0]
const lastCh = testList[testList.length - 1]
const x = '×';

init(codeEncoded).then(res => console.info('done!'))

async function init(codeEncoded: string): Promise<void> {
  const ceSplits = codeEncoded.split(x)

  const currChars = new Array(ceSplits.length).join(firstCh).split('')

  const result = await new Promise<string>(resolve => {
    console.clear();
    (function itv(currChars) {
      const code = mergeCodeSplitAndXChar(
        ceSplits,
        currChars
      )
      console.info('测试值x字符：', currChars.join(' '));
      test(code).then(isValid => {
        if (isValid) {
          resolve(code)
          return;
        }

        const r = changeNextXCode(currChars)

        if (r.isOver) {
          resolve(`居然没有匹配的！已经测试用例使用完毕！最后的测试值为：${code}`);
          return;
        }

        itv(r.data);
      })
    })(currChars)
  })

  console.info(`分析完毕, 拷贝结果请到控制台！结果为：${result}`)
}


async function test(code: string): Promise<boolean> {
  fillInput(code);
  clickBtnCheck();
  const isValid = await new Promise<boolean>(resolve => {
    setTimeout(() => {
      const b = checkResult();
      resolve(b)
    }, 2000);
  })
  return isValid;
}

function fillInput(value: string): void {
  const $input: HTMLInputElement = document.querySelector('#invcode')
  if(!$input){return}
  $input.value = value;
}

function clickBtnCheck(): void {
  const $input: HTMLInputElement = document.querySelector('#invcode')
  if (!$input) { return }
  const $btn = [
    $input.nextSibling,
    $input.nextSibling.nextSibling
  ].filter((e: any) => e && e.tagName && e.tagName.toLowerCase() === 'input')[0]

  const evt = document.createEvent('HTMLEvents');
  evt.initEvent('click', false, false);
  $btn.dispatchEvent(evt)
}

function checkResult(): boolean {
  const $div: HTMLDivElement = document.querySelector('#check_info_invcode')
  if (!$div) { return }
  return ['正在上传', '序列表无效'].every(str => $div.innerHTML.indexOf(str) === -1)
}

/* 获取下一个值，并判断字符是否超出并重置为0了 */
function getNextChar(charOld: string): {
  isReset: boolean;
  data: string;
} {
  if (charOld === lastCh) {
    return {
      isReset: true,
      data: firstCh
    }
  }
  else {
    return {
      isReset: false,
      data: testList[
        testList.indexOf(charOld) + 1
      ]
    }
  }
}

/**
 * 根据当前的测试值更新为下一个测试值
 * @param currChars 指替换的x值的数组，还需与数据进行拼合才能得到测试值code
 * @returns 更新后待测试的x值的数组
 */
function changeNextXCode(currChars: string[]): {
  isOver: boolean,
  data: string[]
} {
  // 判断是否已经over了
  const isAllLast = currChars.every(ch => ch === lastCh)
  if (isAllLast) {
    return {
      isOver: true,
      data: []
    }
  }

  // 如果没over，继续更新
  let isShouldAdd: boolean = true;
  let nextCodeArr = []
  for (let i = currChars.length; i--;) {
    let ch = currChars[i];
    let chNew = ch;
    if (isShouldAdd) {
      const r = getNextChar(ch)
      chNew = r.data;
      isShouldAdd = r.isReset;
    }
    nextCodeArr.unshift(chNew)
  }

  return {
    isOver: false,
    data: nextCodeArr
  }
}

/* 拼合原码split片段和x值数组 */
function mergeCodeSplitAndXChar(
  codeSplits: string[],
  xChars: string[]
): string {
  const codeArr = []
  codeSplits.forEach((split, idx) => {
    codeArr.push(
      split,
      xChars[idx] || ''
    )
  })
  return codeArr.join('')
}